namespace Dcm.Tests
{
    using System;
    using System.Configuration;
    using System.Diagnostics;
    using System.Xml.Linq;
    using DynamicConfigurationManager;
    using Microsoft.CSharp.RuntimeBinder;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    [TestClass]
    public class DcmTests
    {

        #region Public Methods

        [TestMethod]
        public void TestLegacyIncludeSet()
        {
            const string Expected = "success";
            var actual = DynamicConfigurationManager.AppSettings["always"];
            Debug.WriteLine(DynamicConfigurationManager.Log);
            Assert.AreEqual(Expected, actual);
        }

        [TestMethod]
        public void TestLegacyIncludeSetNested()
        {
            const string Expected = "success";
            var actual = DynamicConfigurationManager.AppSettings["always2"];
            Debug.WriteLine(DynamicConfigurationManager.Log);
            Assert.AreEqual(Expected, actual);
        }

        [DependencyOn("app.config")]
        // [TestMethod] // Tests ConnectionSettings
        public void ConnectionSettingTest1()
        {
            ConnectionStringSettings actual = DynamicConfigurationManager.ConnectionStringSetting("dbAlias");

            const string Expected = "TestConnectionString";
            if (actual == null || Expected != actual.ConnectionString)
            {
                Assert.Inconclusive(Utilities.UnreliableTest);
            }
            Assert.AreEqual(Expected, actual);
        }

        //[TestMethod] // Tests ConnectionSettings
        [DeploymentItem("app.config")]
        [DependencyOn("app.config")]
        [DependencyOn("DatabaseConnection?")]
        public void ConnectionSettingTest2()
        {
            const string Expected = "TestConnectionString";
            string actual = Utilities.CatchInconclusive<NullReferenceException>(
                Expected, () => DynamicConfigurationManager.ConnectionString("dbAlias"));

            Assert.AreEqual(Expected, actual);
        }

        [DependencyOn("app.config")]
        [DependencyOn("DatabaseConnection?")]
        // [TestMethod] // Test DynamicValue
        public void DynamicValueTest()
        {
            const string Expected = "testDbAlias";
            string actual = Utilities.CatchInconclusive<RuntimeBinderException>(
                Expected, () => DynamicConfigurationManager.Setting.dbAlias);
            Assert.AreEqual(Expected, actual);
        }

        [DependencyOn("app.config")]
        [TestMethod] // Tests global app settings which are included in every config set
        public void GlobalAppSettingKey1FromConfig()
        {
            string rtn = DynamicConfigurationManager.AppSettings["globalKey1"];
            Assert.AreEqual("globalValue1", rtn);
        }

        [DependencyOn("app.config")]
        [TestMethod] // Tests global app settings which are included in every config set
        public void GlobalAppSettingKey1FromConfigXElement()
        {
            var elem = new XElement(XNamespace.None + "configuration", content: 
                new XElement("DynamicConfigurationSection",
                    //<add key="globalKey1" value="globalValue1" />

                    new XElement("add",
                        new XAttribute("key","globalKey1"),
                        new XAttribute("value","globalValue1")
                    ),
                    new XElement("configMap",
                        new XAttribute("name","TestMultipleAttr"),
                        new XAttribute("hostname",Environment.MachineName),
                        new XAttribute("hostnameRegEx","^" + new string(new[] { Environment.MachineName[0] })),
                        new XElement("add", 
                            new XAttribute("key", "testMultipleAttrKey"),
                            new XAttribute("value", "testMultipleAttrValue1")
                            )
                    )
                )
            );
            var source = DynamicConfigurationManager.GetSection(elem,null);
            string rtn = DynamicConfigurationManager.AppSettings["globalKey1"];
            Assert.AreEqual("globalValue1", rtn);
        }


        [DependencyOn("app.config")]
        [TestMethod] // Tests global app settings which are included in every config set
        public void GlobalAppSettingKey1FromConfigXDocument()
        {
            var elem = new XElement(XNamespace.None + "configuration", content:
                new XElement("DynamicConfigurationSection",
                    //<add key="globalKey1" value="globalValue1" />

                    new XElement("add",
                        new XAttribute("key", "globalKey1"),
                        new XAttribute("value", "globalValue1")
                    ),
                    new XElement("configMap",
                        new XAttribute("name", "TestMultipleAttr"),
                        new XAttribute("hostname", Environment.MachineName),
                        new XAttribute("hostnameRegEx", "^" + new string(new[] { Environment.MachineName[0] })),
                        new XElement("add",
                            new XAttribute("key", "testMultipleAttrKey"),
                            new XAttribute("value", "testMultipleAttrValue1")
                            )
                    )
                )
            );

            var source = DynamicConfigurationManager.GetSection(elem.GetXmlDoc(), null);
            string rtn = DynamicConfigurationManager.AppSettings["globalKey1"];
            Assert.AreEqual("globalValue1", rtn);
        }

        [DeploymentItem("app.config")]
        [DependencyOn("app.config")]
        [TestMethod] // Tests global app settings which are included in every config set
        public void GlobalAppSettingKey1FromConfigPath()
        {
            var source = DynamicConfigurationManager.GetSection("app.config", null);
            string rtn = DynamicConfigurationManager.AppSettings["globalKey1"];
            Assert.AreEqual("globalValue1", rtn);
        }

        [DependencyOn("app.config")]
        [TestMethod] // Tests global app settings which are included in every config set
        public void GlobalAppSettingKey2()
        {
            string rtn = DynamicConfigurationManager.AppSettings["globalKey2"];
            Assert.AreEqual("globalValue2", rtn);
        }

#if FAKES

        [TestMethod]
        public void TestHostNameRegExWithExecutablePath()
        {
            const string Expected = "expected";
            string wd = Directory.GetCurrentDirectory();

            var mapFilters = new Dictionary<Type, string>
                {
                    { typeof(HostnameRegEx_Accessor), Utilities.MachineNameWildcard() },
                    { typeof(ExecutablePath_Accessor), wd }
                };
            string actual = Utilities.ProcessFakeConfig(Expected, mapFilters.AsEnumerable());
            Utilities.AssertWithLog(Assert.AreEqual, Expected, actual);
            //Assert.Fail("Expected exception");
        }

        [TestMethod]
        public void TestHostNameRegExWithExecutablePathLocation()
        {
            const string Expected = "expected";
            string location = Assembly.GetExecutingAssembly().Location;
            location = Path.GetDirectoryName(location);
            var mapFilters = new Dictionary<Type, string>
                {
                    { typeof(HostnameRegEx_Accessor), Utilities.MachineNameWildcard() },
                    { typeof(ExecutablePath_Accessor), location }
                };
            string actual = Utilities.ProcessFakeConfig(Expected, mapFilters.AsEnumerable());
            Utilities.AssertWithLog(Assert.AreEqual, Expected, actual);
        }

#endif

        [DependencyOn("app.config")]
        [DeploymentItem("app.config")]
        [TestMethod]
        public void TestMultipleAttr()
        {
            string rtn = DynamicConfigurationManager.AppSettings["testMultipleAttrKey"];
            Assert.AreEqual(null, rtn);
            //  Assert.AreEqual("testMultipleAttrValue", rtn);
        }

        [DependencyOn("app.config")]
        [DeploymentItem("app.config")]
        [TestMethod]
        public void TestMultipleAttrHappy()
        {
            string rtn = DynamicConfigurationManager.AppSettings["testMultipleAttrKey2"];
            var areEqual = rtn == "testMultipleAttrValue1";
            if (! areEqual)
            {
                System.Diagnostics.Trace.Write(DynamicConfigurationManager.Log);
                System.Diagnostics.Debug.WriteLine(DynamicConfigurationManager.Log);
                Assert.Fail("testMultipleAttrValue1", rtn);
            }
            Assert.AreEqual("testMultipleAttrValue1", rtn);
            //  Assert.AreEqual("testMultipleAttrValue", rtn);
        }

        [TestMethod]
        public void TestStopOnMatchIncludesItemsInCurrentMatch()
        {
            const string Expected = "hostNameValue";

            XElement config =
                Utilities.GenerateFakeDcmWithMapMatch(
                    mapContent: Utilities.GenerateNameValueElement("hostNameKey", Expected));

            string actual = Utilities.ProcessFakeConfig(config, "hostNameKey");
            Assert.AreEqual(Expected, actual);
        }

        #endregion
    }
}

//[Test] // Tests HostName Regular Expression search (example: "dev") 
//public void UpdateLocation()
//{
//    string rtn = DynamicConfigurationManager.AppSettings["updateLocationKey"];
//    Assert.AreEqual("updateLocationValue", rtn);
//}
//[TestMethod] // Tests Configuration database overrides (example: "B000*") 
//public void TestConfigurationDB()
//{
//    Halos.Configuration.DynamicConfigurationManager.LogEnabled = true;
//    string rtn = Halos.Configuration.DynamicConfigurationManager.AppSettings["WSURL"];
//    Assert.AreEqual("http://localhost:8087/", rtn);

//    rtn = Halos.Configuration.DynamicConfigurationManager.AppSettings["WS2URL"];
//    Assert.AreEqual("http://localhost:2/", rtn);
//    //Assert.Ignore( DynamicConfigurationManager.Log );
//}